package com.ywk.base.java8.stream;

import com.ywk.base.java8.optional.User;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 参考连接：https://blog.csdn.net/ss810540895/article/details/126172285
 * @Author zbh
 * @Date 2022/12/23
 */
public class StreamTest {
    private static List<User> userList = new ArrayList<>();

    static {
        userList.add(new User("1",22, "王旭","3",8000));
        userList.add(new User("2",21, "孙萍" ,"5",6000));
        userList.add(new User("3",23, "步传宇","1",10000));
        userList.add(new User("4",18, "蔡明浩","3",8500));
        userList.add(new User("5",17, "郭林杰","4",7000));
        userList.add(new User("6",29, "韩凯","4",12000));
        userList.add(new User("7",22, "韩天琪","2",20000));
        userList.add(new User("8",21, "郝玮","3",15000));
        userList.add(new User("9",19, "胡亚强","2",10000));
        userList.add(new User("10",14, "季恺","1",9000));
        userList.add(new User("11",17, "荆帅","5",8500));
        userList.add(new User("12",16, "姜有琪","1",10000));
//        userList.add(new User("13",16, "姜有琪","1",10000));
    }

    public static void main(String[] args) {
        /*groupingBy 入参类型为 Function，Function的完整语法：("入参")->{return ...},即：(User user)->{return user.getAge();}
        Lambda表达式返回值只有一行代码时可省略花括号（return即可省略），因为入参类型是确定的，所以也可省略入参的参数类型User，然后入参只有一个，
        小括号也可省略，变成：user->user.getAge()，最后代码只是取了user的属性age，又可省略变成：User::getAge*/
        userList.stream().collect(Collectors.groupingBy(
                (User user)->{return user.getAge();}
//                user->user.getAge()
//                User::getAge
        ));
        System.out.println("===========================转换流===========================");
        //转成  HashSet<User>
        HashSet<User> userHashSet = userList.stream().collect(Collectors.toCollection(HashSet::new));
        //Set<User>
        Set<User> userSet = userList.stream().collect(Collectors.toSet());
        //ArrayList<User>
        ArrayList<User> userArrayList = userList.stream().collect(Collectors.toCollection(ArrayList::new));
        //Map<String,User>，注：(k1, k2) -> k1当key重复时取第一条数据，防止key重复时报错，
        Map<String, User> userMap = userList.stream().collect(Collectors.toMap(User::getName, Function.identity(),(k1, k2) -> k1));
        userMap.entrySet().forEach(System.out::println);
        System.out.println("======================================================");
        //filter 用法
        /*List<User> c = userList.stream().filter(i -> {
            return i.getAge() >= 18;
        }).collect(Collectors.toList());*/
        List<User> collect = userList.stream().filter(i -> i.getAge() >= 18).collect(Collectors.toList());

        //map用法
        //年龄加1
        List<User> list = userList.stream().map(i -> {
            i.setAge(i.getAge() + 1);
            return i;
        }).collect(Collectors.toList());

        //flatMap 用法（将一个流中的每个元素都映射到另一个流中，并将这些流连接起来形成一个新的流，即将多个子流合并成一个流）
        //将两个字符数组合并成一个新的字符数组。
        List<String> l1 = Arrays.asList("m,k,l,a","1,3,5,7");
        List<String> l2 = l1.stream().flatMap(s -> {
            // 将每个元素转换成一个stream
            String[] split = s.split(",");
            Stream<String> s2 = Arrays.stream(split);
            return s2;
        }).collect(Collectors.toList());
        System.out.println("处理前的集合：" + l1);
        System.out.println("处理后的集合：" + l2);

        //求总数，求和，求平均数，求最值（一次性统计）
        DoubleSummaryStatistics summarizing = userList.stream().collect(Collectors.summarizingDouble(User::getSalary));
        System.out.println("summarizing="+summarizing);
        //求总数
        Long count = userList.stream().collect(Collectors.counting());
        System.out.println("count="+count);
        //求和
        Optional<Integer> allSalary1 = userList.stream().map(User::getSalary).reduce((x,y)->x+y);
        Optional<Integer> allSalary2 = userList.stream().map(User::getSalary).reduce(Integer::sum);
        Integer reducing = userList.stream().collect(Collectors.reducing(0, User::getSalary, (i, j) -> (i + j)));
        Integer sum = userList.stream().collect(Collectors.summingInt(User::getSalary));
        System.out.println("allSalary1="+allSalary1.get());
        System.out.println("allSalary2="+allSalary2.get());
        System.out.println("reducing="+reducing);
        System.out.println("sum="+sum);

        //求平均值
        Double avg = userList.stream().collect(Collectors.averagingDouble(User::getSalary));
        System.out.println("avg="+avg);

        //求最值
        Optional<Integer> maxSalary1 = userList.stream().map(User::getSalary).reduce(Integer::max);
        Optional<Integer> maxSalary2 = userList.stream().map(User::getSalary).collect(Collectors.maxBy(Integer::compare));
        Optional<Integer> mixSalary = userList.stream().map(User::getSalary).reduce(Integer::min);
        System.out.println("maxSalary1="+maxSalary1.get());
        System.out.println("mixSalary="+mixSalary.get());

        //排序：升序，倒序，双排序
        List<String> sortByAsc= userList.stream().sorted(Comparator.comparing(User::getSalary))
                .map(i->i.getName()+":"+i.getSalary()).collect(Collectors.toList());
        System.out.println("sortByAsc="+sortByAsc);
        List<String> sortByDesc= userList.stream().sorted(Comparator.comparing(User::getSalary).reversed())
                .map(i->i.getName()+":"+i.getSalary()).collect(Collectors.toList());
        System.out.println("sortByDesc="+sortByDesc);
        List<User> moreSort = userList.stream().sorted(Comparator.comparing(User::getAge).thenComparing(User::getAge))
                .collect(Collectors.toList());
        System.out.println("moreSort="+moreSort);

        //通过joining拼接流中的元素
        String result = userList.stream().map(User::getName).collect(Collectors.joining(","));
        System.out.println(result);

        //分区（partitioningBy）与分组（groupingBy）：分区是特殊的分组，它分类依据是true和false
        Map<Integer, List<User>> gro = userList.stream().collect(Collectors.groupingBy(User::getAge));
        Map<Boolean, List<User>> par=userList.stream().collect(Collectors.partitioningBy(i->i.getAge()>=18));
        //计算每个单位下所有员工的总工资
        Map<String, Integer> map = userList.stream().collect(Collectors.groupingBy(User::getUnitId, Collectors.summingInt(User::getSalary)));
        System.out.println(gro);
        System.out.println(par);
        System.out.println("------------");
        map.forEach((k,v)->{System.out.println(k+"-"+v);});

        //合并、去重、限制、跳过
        String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // concat:合并两个流 distinct：去重
        List<String> concat = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        // limit：限制从流中获得前n个数据
        List<Integer> limit = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
        // skip：跳过前n个数据
        List<Integer> skip = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
        System.out.println("concat：" + concat);
        System.out.println("limit：" + limit);
        System.out.println("skip：" + skip);

        //通过foreach进行元素遍历
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
        integerList.stream().forEach(System.out::println);

        //排序:默认升序，倒序：Comparator.reverseOrder()作为入参传入或后面添加方法 reversed()，区别是前者只对应入参参数进行指定排序方式，
        //后者是对前面所有入参参数都进行指定排序，如果两个都用就采用“负负得正”的原理进行排序
        List<User> sort = userList.stream().sorted(
                Comparator.comparing(User::getAge,Comparator.reverseOrder()).
                        thenComparing(User::getSalary).reversed().
                        thenComparing(User::getName)).
                collect(Collectors.toList());

        System.out.println(sort);

        //anyMatch 用法:判断的条件里，任意一个元素成功，返回true
        System.out.println(Stream.of(null, "1", "2", "3").anyMatch(StreamTest::isBlank));
        //allMatch 用法:判断条件里的元素，所有的都是，返回true
        System.out.println(Stream.of(null, null, null, null).allMatch(StreamTest::isBlank));
        //noneMatch 用法:与allMatch相反，判断条件里的元素，所有的都不是，返回true
        System.out.println(Stream.of("0", "1", "2", "3").noneMatch(StreamTest::isBlank));
        System.out.println(StringUtils.isAnyBlank("0", "1", "2", "3"));

        List<String> i = new ArrayList<>();
        i.add("0");i.add("1");i.add("2");i.add("3");i.add("4");
        Iterator<String> iterator = i.iterator();
        while (iterator.hasNext()) {
            String s = iterator.next();
            if ( s=="3") {
                iterator.remove();
            }
        }
        System.out.println(i);
    }

    private static boolean isBlank(Object value) {
        return StringUtils.isBlank(value == null ? null : value.toString());
    }
}
